package com.spring.springboot.sys.core.filter;

/**
 * @author 宋义州
 * @date 2022-07-31  20:34
 * @description
 */

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.spring.springboot.sys.core.constant.BusinessConstant;
import com.spring.springboot.sys.core.model.Result;
import com.spring.springboot.sys.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import javax.annotation.Resource;
import java.lang.reflect.*;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;

@Slf4j
@ControllerAdvice(basePackages = "com.spring.springboot.controller")
public class ResponseAdvice implements ResponseBodyAdvice<Object> {

    @Resource
    private RedisUtils redisUtils;

    @Override
    public boolean supports(@NotNull MethodParameter returnType, @NotNull Class converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(Object body, @NotNull MethodParameter returnType, @NotNull MediaType selectedContentType, @NotNull Class selectedConverterType,
                                  @NotNull ServerHttpRequest request, @NotNull ServerHttpResponse response) {
        //校验是否开启了数据脱敏
        boolean open = true;
        String value = (String) redisUtils.get(BusinessConstant.Desensitization.INFO_ENCRYPTION);
        if (StringUtils.isNotBlank(value)) {
            open = Objects.equals(value, BusinessConstant.Desensitization.OPEN);
        }

        if (open) {
            if (body instanceof Result) {
                Object obj = ((Result) body).getData();
                //data中没有数据、直接返回即可
                if (ObjectUtils.isEmpty(obj)) {
                    return body;
                }
                //是分页查询
                if (obj instanceof Page) {
                    List<?> records = ((Page<?>) obj).getRecords();
                    for (Object record : records) {
                        Field[] fields = record.getClass().getDeclaredFields();
                        if (ArrayUtils.isNotEmpty(fields)) {
                            for (Field field : fields) {
                                informationDesensitization(record, field);
                            }
                        }
                    }
                    return body;
                }
                //是集合
                if (obj instanceof Collection) {
                    Iterator<?> iterator = ((Collection<?>) obj).iterator();
                    if (iterator.hasNext()) {
                        Object next = iterator.next();
                        Field[] fields = next.getClass().getDeclaredFields();
                        if (ArrayUtils.isNotEmpty(fields)) {
                            for (Field field : fields) {
                                informationDesensitization(next, field);
                            }
                        }
                    }
                    return body;
                }
                //是实体类
                Field[] fields = obj.getClass().getDeclaredFields();
                if (ArrayUtils.isNotEmpty(fields)) {
                    for (Field field : fields) {
                        informationDesensitization(obj, field);
                    }
                }
                return body;
            }
        }
        return body;
    }

    /**
     * 信息脱密
     *
     * @param obj Object
     */
    private void informationDesensitization(Object obj) {
        try {
            Field[] fields = obj.getClass().getDeclaredFields();
            if (ArrayUtil.isNotEmpty(fields)) {
                if (ArrayUtil.isNotEmpty(fields)) {
                    for (Field value : fields) {
                        //设置是否允许访问，不是修改原来的访问权限修饰词。
                        value.setAccessible(true);
                        String name = value.getName();
                        if (name.equals("phone") || name.equals("userPhone") || name.equals("telephone")) {
                            String phone = (String) value.get(obj);
                            String mobilePhone = DesensitizedUtil.mobilePhone(phone);
                            value.set(obj, mobilePhone);
                            log.info("参数打印：{}", phone);
                        }
                        if (name.equals("idCard") || name.equals("idNumber") || name.equals("cardNumber")) {
                            String idCard = (String) value.get(obj);
                            String cardNum = DesensitizedUtil.idCardNum(idCard, 6, 4);
                            value.set(obj, cardNum);
                            log.info("参数打印：{}", idCard);
                        }
                        if (name.equals("password") || name.equals("passWord")) {
                            String password = (String) value.get(obj);
                            String secretCode = DesensitizedUtil.password(password);
                            value.set(obj, secretCode);
                            log.info("参数打印：{}", password);
                        }
                    }
                }
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 信息脱密
     *
     * @param obj   object
     * @param field field
     */
    private void informationDesensitization(Object obj, Field field) {
        field.setAccessible(true);
        //判断是否为list
        if (List.class.isAssignableFrom(field.getType())) {
            Type type = field.getGenericType();
            try {
                if (type instanceof ParameterizedType) {
                    field.setAccessible(true);
                    //获取到属性值的字节码
                    Class<?> clazz = field.get(obj).getClass();
                    //反射调用获取到list的size方法来获取到集合的大小
                    Method sizeMethod = clazz.getDeclaredMethod("size");
                    sizeMethod.setAccessible(true);
                    //集合长度
                    int size = (Integer) sizeMethod.invoke(field.get(obj));
                    //循环遍历获取到数据
                    for (int j = 0; j < size; j++) {
                        //反射获取到list的get方法
                        Method getMethod = clazz.getDeclaredMethod("get", int.class);
                        //调用get方法获取数据
                        getMethod.setAccessible(true);
                        //调用get方法获取list中的对象
                        Object u = getMethod.invoke(field.get(obj), j);
                        informationDesensitization(u);
                    }
                }
            } catch (IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
        //不是集合
        String name = field.getName();
        try {
            if (name.equals("phone") || name.equals("userPhone") || name.equals("telephone") || name.equals("applyUserPhone") || name.equals("phoneNo") || name.equals("tel")
                    || name.equals("comePhone") || name.equals("dutyPhone")) {
                String phone = (String) field.get(obj);
                String mobilePhone = DesensitizedUtil.mobilePhone(phone);
                field.set(obj, mobilePhone);
            }
            if (name.equals("idCard") || name.equals("idNumber") || name.equals("cardNumber") || name.equals("certificateNo") || name.equals("comeIdCard")) {
                String idCard = (String) field.get(obj);
                String cardNum = DesensitizedUtil.idCardNum(idCard, 6, 4);
                field.set(obj, cardNum);
            }
            if (name.equals("password")) {
                String password = (String) field.get(obj);
                String secretCode = DesensitizedUtil.password(password);
                field.set(obj, secretCode);
            }
            if (name.equals("name") || name.equals("userName") || name.equals("customerName") || name.equals("username") || name.equals("legalPerson") || name.equals("applyUserName")
                    || name.equals("personName") || name.equals("comeUser") || name.equals("visitUserName") || name.equals("checkUserName") || name.equals("dutyUser")) {
                String userName = (String) field.get(obj);
                String hide = StrUtil.hide(userName, BusinessConstant.IntNum.NUM_ONE, userName.length());
                field.set(obj, hide);
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }

}
